#include "my_http_headers.h"
#include "comm/my_log.h"

void
my_http_headers_add(my_http_headers_t *headers, my_http_header_t *header)
{
    my_http_same_headers_t *same_headers = NULL;

    my_http_same_headers_t target = {.name = header->name};
    my_rbtree_node_t *same_headers_node =
        my_rbtree_lookup(&headers->same_headers_tree, &target.tree_node);
    if (same_headers_node) {
        same_headers = (my_http_same_headers_t *)same_headers_node;
    }

    if (!same_headers) {
        same_headers = my_pool_mem_calloc(headers->pool, sizeof(my_http_same_headers_t));
        my_http_same_headers_init(same_headers);
        same_headers->name = header->name;
        my_rbtree_insert(&headers->same_headers_tree, &same_headers->tree_node);
    }

    my_queue_insert_tail(&same_headers->headers, &header->queue_in_same_headers);
    my_queue_insert_tail(&headers->headers, &header->queue_in_headers);
}

void
my_http_headers_set(my_http_headers_t *headers, my_http_header_t *header)
{
    my_queue_t              *q = NULL;
    my_http_header_t        *tmp_header = NULL;
    my_http_same_headers_t  *same_headers = NULL;

    my_http_same_headers_t  target = {.name = header->name};
    my_rbtree_node_t *same_headers_node =
        my_rbtree_lookup(&headers->same_headers_tree, &target.tree_node);
    if (same_headers_node) {
        same_headers = (my_http_same_headers_t *)same_headers_node;
        while (!my_queue_empty(&same_headers->headers)) {
            q = my_queue_head(&same_headers->headers);
            tmp_header = my_queue_data(q, my_http_header_t, queue_in_same_headers);
            my_queue_remove(&tmp_header->queue_in_same_headers);
            my_queue_remove(&tmp_header->queue_in_headers);
        }
    }

    if (!same_headers) {
        same_headers = my_pool_mem_calloc(headers->pool, sizeof(my_http_same_headers_t));
        my_http_same_headers_init(same_headers);
        same_headers->name = header->name;
        my_rbtree_insert(&headers->same_headers_tree, &same_headers->tree_node);
    }

    my_queue_insert_tail(&same_headers->headers, &header->queue_in_same_headers);
    my_queue_insert_tail(&headers->headers, &header->queue_in_headers);
}

my_http_header_t *
my_http_headers_get(my_http_headers_t *headers, my_str_t *name)
{
    my_http_same_headers_t target = {.name = *name};
    my_rbtree_node_t *same_headers_node =
        my_rbtree_lookup(&headers->same_headers_tree, &target.tree_node);
    if (!same_headers_node) {
        return NULL;
    }

    my_http_same_headers_t  *same_headers = NULL;
    same_headers = (my_http_same_headers_t *)same_headers_node;
    if (my_queue_empty(&same_headers->headers)) {
        return NULL;
    }

    my_queue_t *q = my_queue_head(&same_headers->headers);
    return my_queue_data(q, my_http_header_t, queue_in_same_headers);
}

my_http_same_headers_t *
my_http_headers_values(my_http_headers_t *headers, my_str_t *name)
{
    my_http_same_headers_t target = {.name = *name};
    my_rbtree_node_t *same_headers_node =
        my_rbtree_lookup(&headers->same_headers_tree, &target.tree_node);
    if (!same_headers_node) {
        return NULL;
    }

    return (my_http_same_headers_t *)same_headers_node;
}

void
my_http_headers_del(my_http_headers_t *headers, my_http_header_t *header)
{
    (void)headers;
    my_queue_remove(&header->queue_in_same_headers);
    my_queue_remove(&header->queue_in_headers);
}

void
my_http_headers_del_by_name(my_http_headers_t *headers, my_str_t *name)
{
    my_http_same_headers_t target = {.name = *name};
    my_rbtree_node_t *same_headers_node =
        my_rbtree_lookup(&headers->same_headers_tree, &target.tree_node);
    if (!same_headers_node) {
        return;
    }

    my_queue_t              *q = NULL;
    my_http_header_t        *tmp_header = NULL;
    my_http_same_headers_t  *same_headers =
        (my_http_same_headers_t *)same_headers_node;
    while (!my_queue_empty(&same_headers->headers)) {
        q = my_queue_head(&same_headers->headers);
        tmp_header = my_queue_data(q, my_http_header_t, queue_in_same_headers);
        my_queue_remove(&tmp_header->queue_in_same_headers);
        my_queue_remove(&tmp_header->queue_in_headers);
    }

    my_rbtree_delete(&headers->same_headers_tree, same_headers_node);
}

void
my_http_header_dump(my_http_header_t *header)
{
    char buf[1024];
    // header name: header value\0;
    if (header->name.len + 2 + header->value.len + 1 > (int64_t)sizeof(buf))
    {
        MY_LOG_DEBUG("header is to long");
        return;
    }

    int64_t offset = 0;
    strncpy(buf + offset, header->name.data, (size_t)header->name.len);
    offset += header->name.len;
    buf[offset] = ':';
    offset++;
    buf[offset] = ' ';
    offset++;
    strncpy(buf + offset, header->value.data, (size_t)header->value.len);
    offset += header->value.len;
    buf[offset] = '\0';

    MY_LOG_DEBUG("%s", buf);
}

void
my_http_same_headers_dump(my_http_same_headers_t *same_headers)
{
    my_queue_t          *q = NULL;
    my_http_header_t    *header = NULL;

    q = my_queue_head(&same_headers->headers);
    while(q != &same_headers->headers) {
        header = my_queue_data(q, my_http_header_t, queue_in_same_headers);
        my_http_header_dump(header);
        q = q->next;
    }
}

void
my_http_headers_dump(my_http_headers_t *headers)
{
    my_queue_t          *q = NULL;
    my_http_header_t    *header = NULL;

    q = my_queue_head(&headers->headers);
    while(q != &headers->headers) {
        header = my_queue_data(q, my_http_header_t, queue_in_headers);
        my_http_header_dump(header);
        q = q->next;
    }
}